import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * 游戏主窗口
 * 功能：创建游戏窗口并设置基本参数
 */
class GameWindow extends JFrame {
    public GameWindow() {
        setTitle("深海大作战 - Fish Wars");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setResizable(false);
        add(new GamePanel());  // 添加游戏主面板
        pack();                // 自动调整窗口大小
        setLocationRelativeTo(null); // 窗口居中
    }
}

public class Main {
    public static void main(String[] args) {
        // 使用事件分发线程保证GUI线程安全
        EventQueue.invokeLater(() -> new GameWindow().setVisible(true));
    }
}

/**
 * 方向枚举
 * 功能：定义移动方向和相反方向
 */
enum Direction {
    LEFT(-1, 0), RIGHT(1, 0),
    UP(0, -1), DOWN(0, 1);

    public final int dx;  // X轴方向增量
    public final int dy;  // Y轴方向增量

    Direction(int dx, int dy) {
        this.dx = dx;
        this.dy = dy;
    }

    /**
     * 随机获取一个方向
     */
    public static Direction random() {
        return values()[new Random().nextInt(values().length)];
    }
}

/**
 * 鱼类抽象基类
 * 功能：定义所有鱼类的共同属性和行为
 */
abstract class Fish {
    protected int x, y;        // 坐标
    protected int speed;       // 移动速度
    protected int size;        // 体型大小
    protected Color color;     // 颜色
    protected Direction direction; // 移动方向

    public Fish(int x, int y, int speed, int size, Color color) {
        this.x = x;
        this.y = y;
        this.speed = speed;
        this.size = size;
        this.color = color;
        this.direction = Direction.random(); // 随机初始方向
    }

    public int getX() { return x; }
    public int getY() { return y; }
    public int getSize() { return size; }

    /**
     * 移动方法（需子类实现）
     */
    public abstract void move();

    /**
     * 绘制方法（需子类实现）
     */
    public abstract void draw(Graphics g);

    /**
     * 边界检查
     */
    protected void checkBoundaries() {
        // 水平边界处理
        if (x < 0) {
            x = 0;
            direction = Direction.RIGHT;
        } else if (x > 800 - size) {
            x = 800 - size;
            direction = Direction.LEFT;
        }

        // 垂直边界处理
        if (y < 0) {
            y = 0;
            direction = Direction.DOWN;
        } else if (y > 600 - size) {
            y = 600 - size;
            direction = Direction.UP;
        }
    }
}

/**
 * 玩家鱼类
 * 功能：实现玩家控制逻辑
 */
class PlayerFish extends Fish {
    private int lives = 3;           // 生命值
    private boolean movingUp, movingDown, movingLeft, movingRight; // 移动状态
    private long lastHitTime;        // 上次受伤时间
    private static final int INVINCIBLE_DURATION = 2000; // 无敌时间

    public PlayerFish(int x, int y) {
        super(x, y, 5, 40, Color.YELLOW); // 初始化参数
    }

    /**
     * 设置移动方向
     * @param keyCode 按键代码
     * @param isPressed 按下/释放状态
     */
    public void setMoveDirection(int keyCode, boolean isPressed) {
        switch (keyCode) {
            case KeyEvent.VK_W: movingUp = isPressed; break;
            case KeyEvent.VK_S: movingDown = isPressed; break;
            case KeyEvent.VK_A: movingLeft = isPressed; break;
            case KeyEvent.VK_D: movingRight = isPressed; break;
        }
    }

    @Override
    public void move() {
        // 计算移动向量
        int moveX = (movingRight ? 1 : 0) - (movingLeft ? 1 : 0);
        int moveY = (movingDown ? 1 : 0) - (movingUp ? 1 : 0);

        // 对角线移动速度修正
        if (moveX != 0 && moveY != 0) {
            double diagonalSpeed = speed / Math.sqrt(2);
            x += (int)(moveX * diagonalSpeed);
            y += (int)(moveY * diagonalSpeed);
        } else {
            x += moveX * speed;
            y += moveY * speed;
        }

        // 边界约束（保持鱼在窗口内）
        checkBoundaries();
    }

    // 受伤处理
    public void loseLife() {
        if (System.currentTimeMillis() - lastHitTime > INVINCIBLE_DURATION) {
            lives = Math.max(0, lives - 1);
            lastHitTime = System.currentTimeMillis();
        }
    }

    public int getLives() { return lives; }

    @Override
    public void draw(Graphics g) {
        Graphics2D g2d = (Graphics2D) g.create();
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        // 绘制鱼身
        g2d.setColor(color);
        g2d.fillOval(x, y, size, size/2);

        // 绘制鱼鳍
        g2d.setColor(color.darker());
        g2d.fillPolygon(
                new int[]{x+size/2, x+size, x+size/2},
                new int[]{y, y+size/4, y+size/2},
                3
        );

        // 绘制眼睛
        g2d.setColor(Color.BLACK);
        g2d.fillOval(x + size/3, y + size/6, size/6, size/6);

        // 无敌特效
        if (System.currentTimeMillis() - lastHitTime < INVINCIBLE_DURATION) {
            g2d.setColor(new Color(255, 255, 255, 100));
            g2d.fillOval(x - 5, y - 5, size + 10, size/2 + 10);
        }
        g2d.dispose();
    }
}

/**
 * 大型鱼类（优化追踪逻辑）
 */
class BigFish extends Fish {
    private static final double TRACK_PROBABILITY = 0.6; // 60%概率追踪玩家
    private PlayerFish target;
    private Random rand = new Random();

    public BigFish(int x, int y, PlayerFish target) {
        super(x, y, 3, 60, Color.RED); // 降低移动速度
        this.target = target;
    }

    @Override
    public void move() {
        // 随机决定是否追踪玩家
        if (rand.nextDouble() < TRACK_PROBABILITY) {
            // 追踪逻辑
            int dx = Integer.compare(target.getX(), x);
            int dy = Integer.compare(target.getY(), y);
            x += dx * speed;
            y += dy * speed;
        } else {
            // 随机游动逻辑
            if (rand.nextInt(100) < 20) { // 20%概率改变方向
                direction = Direction.random();
            }
            x += direction.dx * speed;
            y += direction.dy * speed;
        }

        checkBoundaries();
    }

    @Override
    public void draw(Graphics g) {
        Graphics2D g2d = (Graphics2D) g.create();
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        // 绘制身体（三角形）
        g2d.setColor(color);
        int[] xPoints = {x, x + size, x};
        int[] yPoints = {y, y + size/2, y + size};
        g2d.fillPolygon(xPoints, yPoints, 3);

        // 绘制牙齿
        g2d.setColor(Color.WHITE);
        for(int i = 0; i < 3; i++) {
            int yPos = y + size/3 + i*5;
            g2d.drawLine(x + size/2, yPos, x + size, yPos - 3);
        }
        g2d.dispose();
    }
}

/**
 * 小型鱼类（优化随机移动）
 */
class SmallFish extends Fish {
    private Random rand = new Random();

    public SmallFish(int x, int y) {
        super(x, y, 2, 20, Color.GREEN); // 更小的体型和速度
    }

    @Override
    public void move() {
        // 30%概率改变方向
        if (rand.nextInt(100) < 30) {
            direction = Direction.random();
        }

        x += direction.dx * speed;
        y += direction.dy * speed;

        checkBoundaries();
    }

    @Override
    public void draw(Graphics g) {
        Graphics2D g2d = (Graphics2D) g.create();
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        // 绘制身体（圆形）
        g2d.setColor(color);
        g2d.fillOval(x, y, size, size);

        // 绘制尾巴
        g2d.setColor(color.darker());
        g2d.fillArc(x - size/2, y, size, size, 90, 180);
        g2d.dispose();
    }
}

/**
 * 游戏主面板
 * 功能：处理游戏逻辑和渲染
 */
class GamePanel extends JPanel implements ActionListener {
    private static final int MAX_FISH = 30;          // 最大鱼数
    private static final int SPAWN_INTERVAL = 2000;  // 生成间隔（毫秒）

    private PlayerFish player = new PlayerFish(400, 300);
    private List<Fish> fishes = new ArrayList<>();
    private Timer gameTimer = new Timer(30, this);   // 游戏主循环
    private Timer spawnTimer;                        // 鱼群生成计时器
    private int score = 0;

    public GamePanel() {
        setPreferredSize(new Dimension(800, 600));
        setBackground(new Color(0, 50, 100)); // 深海背景色
        initFishes(15);     // 初始生成15条鱼
        setupControls();     // 设置控制
        setupSpawnTimer();   // 启动生成计时器
        gameTimer.start();   // 启动游戏循环
    }

    /**
     * 设置鱼群生成计时器
     */
    private void setupSpawnTimer() {
        spawnTimer = new Timer(SPAWN_INTERVAL, e -> {
            if (fishes.size() < MAX_FISH) {
                spawnNewFish(3); // 每次生成3条
            }
        });
        spawnTimer.start();
    }

    /**
     * 初始化键盘控制
     */
    private void setupControls() {
        InputMap inputMap = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
        ActionMap actionMap = getActionMap();

        // 绑定按键事件
        bindKey(inputMap, actionMap, KeyEvent.VK_W, true);
        bindKey(inputMap, actionMap, KeyEvent.VK_S, true);
        bindKey(inputMap, actionMap, KeyEvent.VK_A, true);
        bindKey(inputMap, actionMap, KeyEvent.VK_D, true);

        bindKey(inputMap, actionMap, KeyEvent.VK_W, false);
        bindKey(inputMap, actionMap, KeyEvent.VK_S, false);
        bindKey(inputMap, actionMap, KeyEvent.VK_A, false);
        bindKey(inputMap, actionMap, KeyEvent.VK_D, false);

        // 窗口显示时自动获取焦点
        addHierarchyListener(e -> {
            if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0) {
                requestFocusInWindow();
            }
        });
    }

    /**
     * 绑定单个按键事件
     */
    private void bindKey(InputMap inputMap, ActionMap actionMap, int keyCode, boolean isPressed) {
        String actionKey = keyCode + (isPressed ? "_PRESS" : "_RELEASE");
        KeyStroke keyStroke = KeyStroke.getKeyStroke(keyCode, 0, !isPressed);

        inputMap.put(keyStroke, actionKey);
        actionMap.put(actionKey, new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                player.setMoveDirection(keyCode, isPressed);
            }
        });
    }

    /**
     * 初始化鱼群
     */
    private void initFishes(int count) {
        Random rand = new Random();
        for (int i = 0; i < count; i++) {
            spawnNewFish(1);
        }
    }

    /**
     * 生成新鱼
     * @param amount 生成数量
     */
    private void spawnNewFish(int amount) {
        Random rand = new Random();
        for (int i = 0; i < amount; i++) {
            int x = rand.nextInt(750);
            int y = rand.nextInt(550);

            // 70%生成小鱼，30%生成大鱼
            if (rand.nextDouble() < 0.7) {
                fishes.add(new SmallFish(x, y));
            } else {
                fishes.add(new BigFish(x, y, player));
            }
        }
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;

        // 绘制所有鱼类
        player.draw(g2d);
        for (Fish fish : fishes) fish.draw(g2d);

        // 绘制游戏信息
        drawHUD(g2d);
    }

    /**
     * 绘制游戏状态面板
     */
    private void drawHUD(Graphics2D g2d) {
        // 半透明背景板
        g2d.setColor(new Color(0, 0, 0, 150));
        g2d.fillRoundRect(10, 10, 180, 80, 15, 15);

        // 生命值显示
        g2d.setFont(new Font("微软雅黑", Font.BOLD, 24));
        g2d.setColor(Color.RED);
        for(int i=0; i<player.getLives(); i++) {
            g2d.drawString("❤", 20 + i*30, 50);
        }

        // 得分显示
        g2d.setColor(Color.WHITE);
        g2d.drawString("得分: " + score, 20, 80);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        player.move();          // 更新玩家位置
        fishes.forEach(Fish::move); // 更新所有鱼的位置
        checkCollisions();      // 碰撞检测
        repaint();              // 重绘画面
    }

    /**
     * 碰撞检测与处理
     */
    private void checkCollisions() {
        List<Fish> toRemove = new ArrayList<>();

        for (Fish fish : fishes) {
            if (checkCollision(player, fish)) {
                if (fish instanceof BigFish) {
                    // 与大型鱼碰撞：扣血并击退
                    player.loseLife();
                    if (player.getLives() <= 0) gameOver();
                    fish.x += (fish.x > player.x ? 50 : -50); // 击退效果
                } else if (fish.getSize() < player.getSize()) {
                    // 吃小型鱼：得分并生成新鱼
                    toRemove.add(fish);
                    score += fish.getSize() * 10;
                }
            }
        }
        fishes.removeAll(toRemove);
    }

    /**
     * 碰撞检测（矩形检测法）
     */
    private boolean checkCollision(Fish a, Fish b) {
        return a.getX() < b.getX() + b.getSize() &&
                a.getX() + a.getSize() > b.getX() &&
                a.getY() < b.getY() + b.getSize() &&
                a.getY() + a.getSize() > b.getY();
    }

    /**
     * 游戏结束处理
     */
    private void gameOver() {
        gameTimer.stop();
        spawnTimer.stop();
        JOptionPane.showMessageDialog(this,
                "游戏结束！最终得分: " + score,
                "游戏结束",
                JOptionPane.INFORMATION_MESSAGE);
        System.exit(0);
    }
}